#ifndef _MCMC_GIBBSLEARNING
#define _MCMC_GIBBSLEARNING

#include "Matrix.h"
#include "mcRaster.h"
#include "mcRasterColor.h"
#include "mcRand.h"
#include "mcmcImageFilters.h"
#include "mcmcPLE.h"

//#define _LEARN_COLOR
//#define _PRECOMPUTE

///////////////////////////////////////////////////////////////
// Maximum psedo-likelihood estimator
class MPLE_Iid
{
public:
	// constructoions and destructions
	MPLE_Iid();
	~MPLE_Iid();

	// operations
	virtual void	Set(const int num_label,const int nlabel1, mcmcMatrix<int> &mx_label,const int num_f, const irmm_Rect bd);
	virtual void	SetEachFilter(const int ifilter, Raster<double> &ras, double min_b, double max_b, double delta);
	virtual void	Learn(const int time=4000);

public:
	SimpleMatrix<Gibbs_B>	mx_beta;

protected:
	SimpleMatrix<Histogram>	mx_histogram;
	SimpleMatrix<Histogram>	mx_histogram_syn;
	Raster<double>			*pras[20];
	int						num_filters;
	irmm_Rect				bound;
	int						num_label;
	int						nlabel;
	mcmcMatrix<int>				*pmx_label;
	mcmcMatrix<double>			mx_Z;
};

///////////////////////////////////////////////////////////////
class MPLE_Iid_Luv : public MPLE_Iid
{
public:
	// construction & destruction
	MPLE_Iid_Luv();
	~MPLE_Iid_Luv();

public:
	// operations
	virtual void	Set(const int num_label,const int nlabel1, mcmcMatrix<int> &mx_label,const irmm_Rect bd);
	virtual void	SetData(Raster<double> &rasL, Raster<double> &rasU, Raster<double> &rasV,
						    Raster<double> &rasLU, Raster<double> &rasLV, Raster<double> &rasUV,
						    mcmcVector<double> &vc_min, mcmcVector<double> &vc_max, mcmcVector<double> &vc_delta);
	virtual void	Learn(const int time=1000);
	virtual void	Synthesiz(Raster_Color<uchar> &image_color);
	inline	double	Prob(const int k, const double l, const double u, const double v, const bool bDivideZ=true);

protected:
	mcmcVector<double>	vc_min_b;
	mcmcVector<double>	vc_max_b;
	mcmcVector<double>	vc_delta;
};

inline double MPLE_Iid_Luv::Prob(const int k, const double l, const double u, const double v, const bool bDivideZ)
{
	double prob=0.0;

	// L
	prob += mx_beta(k,0).GetBin(l);
	// U
	prob += mx_beta(k,1).GetBin(u);
	// V
	prob += mx_beta(k,2).GetBin(v);
	// L+U
	prob += mx_beta(k,3).GetBin(l+u);
	// L+V
	prob += mx_beta(k,4).GetBin(l+v);
	// U+V
	prob += mx_beta(k,5).GetBin(u+v);

	prob = exp(-prob);
	if (bDivideZ)
		prob = prob/mx_Z(k);
	return prob;
}

class MPLE_Learning
{
public:
	// construction & destruction
	MPLE_Learning(){presp=NULL;};
	~MPLE_Learning(){presp=NULL;};

	virtual void	Set(MCMC_FilterResp	&presp1){presp=&presp1;};
	virtual void	Set(MCMC_FilterResp	&presp1, mcmcMatrix<int> &mx_map, mcmcMatrix<int> &mx_par,
		                const int biggestrowsize, const int biggestcolsize)
	{
		presp				= &presp1;
		biggest_rowsize		= biggestrowsize;
		biggest_colsize		= biggestcolsize;
		p_mx_cluster_map	= &mx_map;
	};

	inline double	GetD(const int t)
	{
		if (t<20)		return 0.5;
		else if	(t<100)	return 0.4;
		else if (t<200)	return 0.3;
		else			return 0.2;
	};

protected:
	MCMC_FilterResp	*presp;
	int				biggest_rowsize,biggest_colsize;
	mcmcMatrix<int>		*p_mx_cluster_map;
	int				current_patch;
	bool			bprecompute_resp;
};

///////////////////////////////////////////////////////////////
class MPLE_Luv : public MPLE_Learning
{
public:
	MPLE_Luv();
	~MPLE_Luv();

	virtual void	Learn(const int time, const bool bprecompute, const int kcluster);
	virtual void	ComputeEnergyMap(mcmcMatrix<double> &mx_prob_map);
	virtual void	Synthesiz(Raster_Color<uchar> &image_color, const int kcluster=-1);
	virtual void	SaveBetaToFile(char *file_name);
	virtual void	ReadBetaFromFile(char *file_name);
	virtual void	FilteringOnNewImage(Raster_Color<uchar> &image_color);

protected:
	virtual void	Initialization(void);
	virtual void	ComputeSiteHistogramInAdvance(const int kcluster);
			 double	Energy(const double l, const double u, const double v);
			 double Energy(const int k_l, const int k_u, const int k_v,
				           const int k_lu,const int k_lv,const int k_uv);
			void	UpdateHistogramSyn(void);
			void	UpdateHistogramSynTemp(const double prob, const double l, const double u, const double v, const int row, const int col);
			bool	UpdateBeta(const double d);
			void	ClearHistogramSyn(void);
			void	ClearHistogramSynTemp(void);
			void	UpdateFilterRespAtOneSite(const int j, const int i, const double l, const double u, const double v);
			void	ExpandImageForComputingProb(const int size4row, const int size4col);

protected:
	virtual bool	ValidLUV(const double l, const double u, const double v);

private:
	virtual void	SaveRespHistToFile(const int row);
	virtual void	ReadRespHistFromFile(const int row);

public:
	FRAME_One_Channel		frame_channel_l,frame_channel_u,frame_channel_v;

protected:
	MCMC_FilterResp	*presp;

	FRAME_One_Channel		frame_channel_lu,frame_channel_lv,frame_channel_uv;

private:
	SimpleMatrix<Histogram>	*pmx_resp_hist_l,*pmx_resp_hist_u,*pmx_resp_hist_v;
	bool					bprecompute_resp;
	int						*p_important_color_index[6];
	double					*p_important_color[3];
	int						num_total_color;
};

///////////////////////////////////////////////////////////////
class MPLE_It : public MPLE_Learning
{
public:
	// construction & destruction
	MPLE_It();
	~MPLE_It();

	virtual void	Learn(const int time,const bool bprecompute, const int kcluster);
	virtual void	ComputeEnergyMap(mcmcMatrix<double> &mx_prob_map);
	virtual void	Synthesiz(Raster<uchar> &image, const int kcluster=-1);
	virtual void	SaveBetaToFile(char *file_name);
	virtual void	ReadBetaFromFile(char *file_name);
	virtual void	FilteringOnNewImage(Raster<uchar> &image_intensity);

protected:
	virtual void	Initialization(void);
	virtual void	ComputeSiteHistogramInAdvance(const int kcluster);
			 double	Energy(const double it);
			 double Energy(const int k_it);
			void	UpdateHistogramSyn(void);
			void	UpdateHistogramSynTemp(const double prob, const double it, const int row, const int col);
			bool	UpdateBeta(const double d);
			void	ClearHistogramSyn(void);
			void	ClearHistogramSynTemp(void);
			void	UpdateFilterRespAtOneSite(const int j, const int i, const double it);
			void	ExpandImageForComputingProb(const int size4row, const int size4col);

protected:
	virtual bool	ValidIt(const double it);

private:
	virtual void	SaveRespHistToFile(const int row);
	virtual void	ReadRespHistFromFile(const int row);

public:
	FRAME_One_Channel		frame_channel_it;

private:
	SimpleMatrix<Histogram>	*pmx_resp_hist_it;
	int						*p_important_it_index;
	double					*p_important_it;
	int						num_total_it;
};


///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// learn all the pseudo likelihood parameters for a given clustered image

class MCMC_Learn_PLE_Clusters
{
public:
	// construction & destruction
	MCMC_Learn_PLE_Clusters();
	~MCMC_Learn_PLE_Clusters();

	// operations
	void			Set(mcmcMatrix<int> &mx_map, MCMC_FilterResp &resp);
	void			LearnPLE4Clusters(Gibbs_B *pref_l, Gibbs_B *pref_u, Gibbs_B *pref_v,
									  mcmcMatrix<double> *pmx_energy_map=NULL, Raster_Color<uchar> *pras_syn=NULL);
	void			LearnPLE4Clusters(Gibbs_B *pref_it,mcmcMatrix<double> *pmx_energy_map=NULL, Raster<uchar> *pras_syn=NULL);

private:
	mcmcMatrix<int>		GetOptimalDivision(const int size_whole, const int size_patch,
									   const int size_bound_cut, const int size_overlap,
									   int *p_size_biggest=NULL);
	void			PrepareForPasting(void);
	void			PasteAnImageToLearn(const int kcluster);

public:
	SimpleMatrix<bool>		vc_valid_clusters;	// valid clusters for pesudo likelihood estimation

protected:
	MCMC_FilterResp			*presp;
	int						num_clusters;
	mcmcVector<int>			vc_size_clusters;
	mcmcMatrix<int>				mx_cluster_map;
	int						biggest_rowsize,biggest_colsize;
	mcmcMatrix<int>				mx_partition;
	MPLE_Luv				mple_luv;
	MPLE_It					mple_it;

private:
	Raster_Color<uchar>		image_paste;
	Raster<int>				ras_connected_cluster;
	RF						rf_connected_cluster;
	int						num_connected_cluster;
	McPoint2D				*p_cluster_center;
	mcmcVector<int>			vc_size_connected;
	mcmcVector<int>				vc_cluster_index;
	irmm_Rect				*pbound;
};

bool WriteToPPM(Raster_Color<uchar> &image_color, char *file_name);
bool WriteToPPM(Raster<uchar> &image, char *file_name);
bool ReadFromPPM(Raster_Color<uchar> &image_color, char *file_name);
bool ReadFromPPM(Raster<uchar> &image, char *file_name);

template<class Tp>
bool WriteBigMatrix(mcmcMatrix<Tp> &matrix, char *file_name)
{
	ofstream file;

	file.open(file_name, ios::out | ios::binary);
	if (file.fail())
		return false;

	matrix >> file;

	return true;
}

template<class Tp>
bool ReadBigMatrix(mcmcMatrix<Tp> &matrix, char *file_name)
{
	ifstream file;

	file.open(file_name, ios::in | ios::binary | ios::_Nocreate);
	if (file.fail())
		return false;

	matrix << file;

	return true;
}

#endif
